package com.hxkj.controller;

import com.hxkj.client.service.DefaultAvatarServiceClient;
import com.hxkj.client.service.NormalNotificationClient;
import com.hxkj.constant.Constants;
import com.hxkj.domain.enums.UserExceptionEnum;
import com.hxkj.domain.po.DefaultAvatar;
import com.hxkj.domain.po.LoginToken;
import com.hxkj.domain.po.NormalEmail;
import com.hxkj.domain.po.SysUser;
import com.hxkj.domain.result.UserParameterDataStruct;
import com.hxkj.service.UserService;
import com.hxkj.token.TokenGenerator;
import com.hxkj.utils.MD5Utils;
import com.platform.common.domain.exception.CustomException;
import com.platform.common.domain.result.ResultDataStruct;
import com.platform.common.domain.result.ResultMessageStruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.Objects;
import java.util.concurrent.Callable;

/**
 * created by kezhijie on 2018/8/21 9:47.
 * email to kezhijie@hxoss.com
 */
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {


    @Autowired
    private UserService userService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private TokenGenerator tokenGenerator;

    @Autowired
    private NormalNotificationClient normalNotificationClient;

    @Autowired
    private DefaultAvatarServiceClient defaultAvatarServiceClient;
    /**
     * 测试连通性
     * @return
     */
    @GetMapping(value = "/entry")
    public String entry(){
        return "<h1>@_@<br>^-^<br>*_*</h1>";
    }

    /**
     * 登录入口
     * @param sysUser 登录信息
     * @throws Exception
     */
    @PostMapping(value = "/login", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public Callable<ResultDataStruct<LoginToken>> login(@RequestBody SysUser sysUser) throws Exception {
        // 生成token 信息
        return () ->  userService.login(sysUser);
    }

    @PostMapping(value = "exists", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public Callable<ResultDataStruct<SysUser>> exists(@RequestBody SysUser sysUser) {
        return () -> {
            ResultDataStruct<SysUser> resultDataStruct = new ResultDataStruct<>();
          if (Objects.isNull(sysUser) || Objects.isNull(sysUser.getPhone()) || Objects.isNull(sysUser.getEmail())) {
              resultDataStruct.setCode(UserExceptionEnum.USERINFO_INVALID.getCode());
              resultDataStruct.setMessage(UserExceptionEnum.USERINFO_INVALID.getMsg());
              return resultDataStruct;
          }

          SysUser exists = userService.existsUser(sysUser);

          if (Objects.isNull(exists)) {
              resultDataStruct.setCode(UserExceptionEnum.USER_NOT_EXIST.getCode());
              resultDataStruct.setMessage(UserExceptionEnum.USER_NOT_EXIST.getMsg());
          } else {
              resultDataStruct.setCode(200);
              resultDataStruct.setMessage("成功");
              resultDataStruct.setData(exists);
          }

          return resultDataStruct;
        };
    }

    /**
     * 通过邮箱注册
     * @param userParameterDataStruct
     * @throws Exception
     */
    @PostMapping(value = "/registerByEmail")
    public Callable<ResultMessageStruct> registerByEmail(@RequestBody UserParameterDataStruct<SysUser, String> userParameterDataStruct) throws  Exception {
        return () -> {
            ResultMessageStruct resultMessageStruct = new ResultMessageStruct();

            SysUser sysUser = userParameterDataStruct.getData();
            String msg = userParameterDataStruct.getCode();

            try {
                if (StringUtils.isEmpty(sysUser.getEmail()))
                    throw new CustomException(UserExceptionEnum.USER_EMAIL_IS_NULL);
                if (StringUtils.isEmpty(sysUser.getPassword()))
                    throw new CustomException(UserExceptionEnum.USER_PASSWORD_NOT_NULL);
                if (StringUtils.isEmpty(msg))
                    throw new CustomException(UserExceptionEnum.EMAIL_MSG_IS_NULL);

                SysUser exists = userService.existsUser(sysUser);

                if (Objects.nonNull(exists) && exists.getUserStatus().toString().equals("1")) {
                    sendEmail(sysUser, msg);
                    throw new CustomException(UserExceptionEnum.USER_NOT_ACTIVE);
                }

                sysUser.setUserStatus(Byte.valueOf("1"));
                register(sysUser);

                // 发送激活邮件
                sendEmail(sysUser, msg);

                resultMessageStruct.setCode(200);
                resultMessageStruct.setMessage("成功");
            } catch (CustomException e) {
                resultMessageStruct.setCode(e.getCode().getCode());
                resultMessageStruct.setMessage(e.getMessage());
            } catch (Exception e) {
                resultMessageStruct.setCode(500);
                resultMessageStruct.setMessage(e.getMessage());
            }

            return resultMessageStruct;
        };
    }

    /**
     * 通过手机注册
     * 此接口调用之前，需要先调用动态码接口
     * 动态码：com.hxkj.controller.ValidateCodeController#mobilecode(com.hxkj.domain.po.User)
     * @param userParameterDataStruct
     * @throws Exception
     */
    @PostMapping(value = "/registerByPhone")
    public Callable<ResultDataStruct<LoginToken>> registerByPhone(@RequestBody UserParameterDataStruct<SysUser, String> userParameterDataStruct) throws  Exception {
        return () -> {
            ResultDataStruct<LoginToken> resultDataStruct = new ResultDataStruct<>();
            try {
                if (Objects.isNull(userParameterDataStruct.getCode()))
                    throw new CustomException(UserExceptionEnum.REQUIRE_VALIDATECODE);
                if (Objects.isNull(userParameterDataStruct.getData().getPhone()))
                    throw new CustomException(UserExceptionEnum.USER_PHONE_IS_NULL);
                String storeKey = Constants.REDIS_PREFIX_TELEPHONE_LOGIN + userParameterDataStruct.getData().getPhone();
                if (Objects.isNull(redisTemplate.boundValueOps(storeKey).get()))
                    throw new CustomException(UserExceptionEnum.VALIDATECODE_INVALID);

                String originCode = redisTemplate.boundValueOps(storeKey).get().toString();
                if (!originCode.equalsIgnoreCase(userParameterDataStruct.getCode()))
                    throw new CustomException(UserExceptionEnum.VALIDATECODE_IS_ERROR);

                // 移除验证码
//               redisTemplate.delete(storeKey);

                register(userParameterDataStruct.getData());

                LoginToken loginToken = tokenGenerator.generatorLoginToken(null, userParameterDataStruct.getData().getUserAccount(), userParameterDataStruct.getData().getUserId());

                resultDataStruct.setCode(200);
                resultDataStruct.setMessage("成功");
                resultDataStruct.setData(loginToken);
            } catch (CustomException e) {
                resultDataStruct.setCode(e.getCode().getCode());
                resultDataStruct.setMessage(e.getMessage());
            } catch (Exception e) {
                log.error("手机注册异常， 用户名：" + userParameterDataStruct.getData().getPhone(), e);
                resultDataStruct.setCode(500);
                resultDataStruct.setMessage(e.getMessage());
            }
            return resultDataStruct;
        };
    }

    private void register(SysUser sysUser) throws Exception {

        // 添加随机默认头像
        DefaultAvatar defaultAvatar = defaultAvatarServiceClient.getRandomInfo().getData();

        if (Objects.nonNull(defaultAvatar))
            sysUser.setAvatar(defaultAvatar.getImgPath());
        else
            log.warn("未取到随机默认头像，请在CMS中进行默认头像的配置");

        ResultMessageStruct resultMessageStruct = userService.save(sysUser);

        if (resultMessageStruct.getCode() != 200) {
            throw new CustomException(UserExceptionEnum.getEnumByCode(resultMessageStruct.getCode()));
        }
    }

    /**
     * 通过手机动态码登录
     * @param userParameterDataStruct
     * @return
     * @throws Exception
     */
    @PostMapping(value = "dynamicLogin")
    public Callable<ResultDataStruct<LoginToken>> dynamicLogin(@RequestBody UserParameterDataStruct<SysUser, String> userParameterDataStruct) throws Exception {
        return () -> {
            ResultDataStruct<LoginToken> resultDataStruct = new ResultDataStruct<>();
            SysUser sysUser = userParameterDataStruct.getData();
            String code = userParameterDataStruct.getCode();
            try {
                // 组成存储 key
                String storeKey = Constants.REDIS_PREFIX_TELEPHONE_LOGIN + sysUser.getPhone();

                if (Objects.isNull(redisTemplate.boundValueOps(storeKey).get())) {
                    throw new CustomException(UserExceptionEnum.VALIDATECODE_INVALID);
                }

                String originCode = redisTemplate.boundValueOps(storeKey).get().toString();

                if (!originCode.equalsIgnoreCase(code))
                    throw new CustomException(UserExceptionEnum.VALIDATECODE_IS_ERROR);

                SysUser existsSysUser = userService.existsUser(sysUser);

                if (existsSysUser.getUserStatus() == Byte.valueOf("1"))
                    throw new CustomException(UserExceptionEnum.USER_NOT_ACTIVE);

                if (!Objects.nonNull(existsSysUser))
                    throw new CustomException(UserExceptionEnum.USER_LOGIN_INFO_INVAILD);

                LoginToken loginToken = tokenGenerator.generatorLoginToken(null, existsSysUser.getUserAccount(), existsSysUser.getUserId());

//                redisTemplate.delete(storeKey);

                resultDataStruct.setCode(200);
                resultDataStruct.setMessage("成功");
                resultDataStruct.setData(loginToken);
            } catch (CustomException e) {
                resultDataStruct.setCode(e.getCode().getCode());
                resultDataStruct.setMessage(e.getMessage());
            } catch (Exception e){
                resultDataStruct.setCode(500);
                resultDataStruct.setMessage(e.getMessage());
            }

            return resultDataStruct;
        };
    }

    /**
     * 如果没有oldPassword就是忘记密码
     * 如果有oldPassword就是修改密码
     * @param userParameterDataStruct
     * @throws Exception
     */
    @PostMapping(value = "updatePassword")
    public Callable<ResultMessageStruct> updatePassword(@RequestBody UserParameterDataStruct<SysUser, String> userParameterDataStruct) throws Exception {
        return () -> {
            ResultMessageStruct resultMessageStruct = new ResultMessageStruct();
            SysUser sysUser = userParameterDataStruct.getData();
            String oldPassword = userParameterDataStruct.getCode();
            try {
                if (Objects.isNull(sysUser) || Objects.isNull(sysUser.getPassword()) || (Objects.isNull(sysUser.getPhone()) && Objects.isNull(sysUser.getEmail())))
                    throw new CustomException(UserExceptionEnum.USERINFO_INVALID);

                SysUser existsSysUser = userService.existsUser(sysUser);

                if (existsSysUser.getUserStatus() == Byte.valueOf("1"))
                    throw new CustomException(UserExceptionEnum.USER_NOT_ACTIVE);

                if (Objects.isNull(existsSysUser))
                    throw new CustomException(UserExceptionEnum.USER_NOT_EXIST);

                if (Objects.isNull(oldPassword)) { // 忘记密码

                    existsSysUser.setPassword(sysUser.getPassword());
                    resultMessageStruct = userService.updatePassword(existsSysUser);

                    if (resultMessageStruct.getCode() != 200)
                        throw new CustomException(UserExceptionEnum.UPDATE_PASSWORD_ERROR);

                } else { //修改密码

                    boolean verify = MD5Utils.validPassword(oldPassword, existsSysUser.getPassword(), existsSysUser.getSalt());

                    if (verify) { // 原密码输入正确
                        existsSysUser.setPassword(sysUser.getPassword());
                        resultMessageStruct = userService.updatePassword(existsSysUser);

                        if (resultMessageStruct.getCode() != 200)
                            throw new CustomException(UserExceptionEnum.UPDATE_PASSWORD_ERROR);

                    } else {
                        throw new CustomException(UserExceptionEnum.USER_PASSWORD_IS_NO);
                    }

                }

                resultMessageStruct.setCode(200);
                resultMessageStruct.setMessage("成功");
            } catch (CustomException e) {
                resultMessageStruct.setCode(e.getCode().getCode());
                resultMessageStruct.setMessage(e.getMessage());
            } catch (Exception e) {
                resultMessageStruct.setCode(500);
                resultMessageStruct.setMessage(e.getMessage());
            }

            return resultMessageStruct;
        };
    }

    @GetMapping("/logout")
    public Callable<ResultMessageStruct> logout(@RequestParam("token") String token) throws Exception {
        return () -> {
            ResultMessageStruct resultMessageStruct = new ResultMessageStruct();
            try {
                tokenGenerator.quit(token);
                resultMessageStruct.setCode(200);
                resultMessageStruct.setMessage("成功");
            } catch (CustomException e) {
                resultMessageStruct.setCode(e.getCode().getCode());
                resultMessageStruct.setMessage(e.getMessage());
            } catch (Exception e) {
                resultMessageStruct.setCode(500);
                resultMessageStruct.setMessage(e.getMessage());
            }
            return resultMessageStruct;
        };
    }

    /**
     * 用于给到除用户中心外其它站点访问
     * 特地独立出来，避免重复。
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/logoutBySite")
    public Callable<ResultMessageStruct> logoutBySite(@RequestBody String token) throws Exception {
        return () -> {
            ResultMessageStruct resultMessageStruct = new ResultMessageStruct();
            try {
                tokenGenerator.quit(token);
                resultMessageStruct.setCode(200);
                resultMessageStruct.setMessage("成功");
            } catch (CustomException e) {
                resultMessageStruct.setCode(e.getCode().getCode());
                resultMessageStruct.setMessage(e.getMessage());
            } catch (Exception e) {
                resultMessageStruct.setCode(500);
                resultMessageStruct.setMessage(e.getMessage());
            }
            return resultMessageStruct;
        };
    }

    /**
     * 激活邮箱注册的用户
     * @param sysUser
     * @throws Exception
     */
    @PostMapping("active")
    public Callable<ResultMessageStruct> active(@RequestBody SysUser sysUser) throws Exception {
        return () -> {
            ResultMessageStruct resultMessageStruct = new ResultMessageStruct();

            try {
                if (Objects.isNull(sysUser) || Objects.isNull(sysUser.getEmail()))
                    throw new CustomException(UserExceptionEnum.USER_EMAIL_IS_NULL);

                SysUser notActive = userService.existsUser(sysUser);

                if (Objects.isNull(notActive))
                    throw new CustomException(UserExceptionEnum.USER_NOT_EXIST);
                if (notActive.getUserStatus().toString().equals("0"))
                    throw new CustomException(UserExceptionEnum.USER_ACTIVATED);
                notActive.setUserStatus(Byte.valueOf("0"));

                resultMessageStruct = userService.update(notActive);
            } catch (CustomException e) {
                resultMessageStruct.setCode(e.getCode().getCode());
                resultMessageStruct.setMessage(e.getMessage());
            } catch (Exception e) {
                resultMessageStruct.setCode(500);
                resultMessageStruct.setMessage(e.getMessage());
            }
            return resultMessageStruct;
        };
    }

    @PostMapping("sendActiveEmail")
    public Callable<ResultMessageStruct> sendActiveEmail(@RequestBody UserParameterDataStruct<SysUser, String> userParameterDataStruct) throws Exception {
        return () -> {
            ResultMessageStruct resultMessageStruct = new ResultMessageStruct();

            SysUser sysUser = userParameterDataStruct.getData();
            String msg = userParameterDataStruct.getCode();
            try {
                if (Objects.isNull(sysUser) || StringUtils.isEmpty(sysUser.getEmail()))
                    throw new CustomException(UserExceptionEnum.USERINFO_INVALID);
                if (StringUtils.isEmpty(msg))
                    throw new CustomException(UserExceptionEnum.EMAIL_MSG_IS_NULL);

                sendEmail(sysUser, msg);

                resultMessageStruct.setCode(200);
                resultMessageStruct.setMessage("成功");
            } catch (CustomException e) {
                resultMessageStruct.setCode(e.getCode().getCode());
                resultMessageStruct.setMessage(e.getMessage());
            } catch (Exception e) {
                resultMessageStruct.setCode(500);
                resultMessageStruct.setMessage(e.getMessage());
            }

            return resultMessageStruct;
        };
    }

    private void sendEmail(SysUser sysUser, String msg) throws Exception {
        NormalEmail normalEmail = new NormalEmail();
        normalEmail.setReceiver(sysUser.getEmail());
        normalEmail.setTopic("【中亿财经网】激活邮件");
        normalEmail.setMsg(msg);

        ResultMessageStruct resultMessageStruct = normalNotificationClient.sendEmail(normalEmail);
        if (resultMessageStruct.getCode() != 200)
            throw new CustomException("邮件发送失败");
    }

}
